package com.penghaonan.appframework.utils.listview

import android.content.Context
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import android.view.animation.Animation
import android.widget.BaseAdapter
import androidx.core.os.bundleOf
import com.penghaonan.appframework.anim.AnimationListenerAdapter
import com.penghaonan.appframework.utils.CollectionUtils
import com.penghaonan.appframework.utils.Logger.Companion.e
import com.penghaonan.appframework.utils.ThreadUtils.Companion.getThreadPool
import com.penghaonan.appframework.utils.threadpool.AThreadPool
import com.penghaonan.appframework.utils.threadpool.ThreadPoolTask
import java.util.LinkedList

open class ItemAdapter<T> : BaseAdapter {
    private val mDatas: MutableList<T> = ArrayList()
    private val checkedIndexSet: MutableSet<Int> = HashSet()
    private var mViewClass: Class<out BaseItemView<T>>? = null
    private var mCheckMode = false
    private var reversed = false
    private var currentPosition = -1
    private var enterAnimGenerator: (() -> Animation)? = null
    private var dividerTime = 0L
    private var env: Bundle = bundleOf()

    private var threadPool: AThreadPool? = null

    var beforeItemViewBindListener: ((data: T, view: BaseItemView<T>) -> Unit)? = null

    constructor() {
        init()
    }

    constructor(
        list: List<T>,
        viewClass: Class<out BaseItemView<T>>?,
    ) {
        data = list
        mViewClass = viewClass
        init()
    }

    private fun init() {
    }

    fun setEnterAnim(enterAnimGenerator: (() -> Animation)?, dividerTime: Long) {
        this.enterAnimGenerator = enterAnimGenerator
        this.dividerTime = dividerTime
    }

    fun setEnv(bundle: Bundle) {
        env.putAll(bundle)
    }

    open fun getData(index: Int): T {
        return mDatas[index]
    }

    fun removeData(data: T) {
        mDatas.remove(data)
    }

    var data: List<T>
        get() = mDatas
        set(list) {
            mDatas.clear()
            mDatas.addAll(list)
        }

    fun setReversed(reversed: Boolean) {
        this.reversed = reversed
    }

    fun setView(viewClass: Class<out BaseItemView<T>>?) {
        mViewClass = viewClass
    }

    override fun getCount(): Int {
        return CollectionUtils.size(mDatas)
    }

    override fun getItem(arg0: Int): T {
        return if (mDatas.size == 0) Any() as T else mDatas[calculateIndex(arg0)]
    }

    private fun calculateIndex(arg0:Int):Int {
        return if (reversed) mDatas.size - arg0 - 1 else arg0
    }

    override fun getItemId(arg0: Int): Long {
        return arg0.toLong()
    }

    private val onItemCheckChangedListener =
        IItemCheckListener { index: Int, checked: Boolean ->
            if (checked != isChecked(index)) {
                onChecked(index, checked)
            }
        }

    override fun getView(index: Int, convertView: View?, arg2: ViewGroup): View {
        val view: BaseItemView<T>
        if (convertView == null) {
            try {
                view = mViewClass!!.getConstructor(Context::class.java)
                    .newInstance(arg2.context)
                view.setAdapter(this)
                view.onInit(env)
                view.setOnCheckedChangeListener(onItemCheckChangedListener)
            } catch (e: Exception) {
                e("View class error. " + mViewClass!!.name)
                val constructors = mViewClass!!.constructors
                e("Constructor count: " + constructors.size)
                for (constructor in constructors) {
                    e("Constructor:$constructor")
                }
                e(e)
                return object : EmptyItemView(arg2.context) {}
            }
        } else {
            view = convertView as BaseItemView<T>
        }
        val data = getItem(index)
        view.setCheckable(mCheckMode)

        if (threadPool == null) {
            threadPool = getThreadPool(view.context)
        }
        beforeItemViewBindListener?.let {
            it(data, view)
        }
        view.setData(data, threadPool, calculateIndex(index))
        if (mCheckMode) {
            view.setChecked(isChecked(index))
        }
        currentPosition = index
        enterAnimGenerator?.let {
            view.visibility = View.INVISIBLE
            view.postDelayed({
                view.startAnimation(it().apply {
                    setAnimationListener(object : AnimationListenerAdapter() {
                        override fun onAnimationStart(animation: Animation?) {
                            view.visibility = View.VISIBLE
                        }
                    })
                })
            }, dividerTime * index)
        }
        return view
    }

    var isCheckMode: Boolean
        /**
         * 是否是多行模式
         */
        get() = mCheckMode
        /**
         * 多行模式
         */
        set(checkMode) {
            mCheckMode = checkMode
            notifyDataSetChanged()
        }

    /**
     * 是否已选中
     */
    open fun isChecked(index: Int): Boolean {
        return checkedIndexSet.contains(index)
    }

    fun isChecked(data: T): Boolean {
        val index = mDatas.indexOf(data)
        return isChecked(index)
    }

    open fun onChecked(index: Int, checked: Boolean) {
        if (checked) {
            checkedIndexSet.add(index)
        } else {
            checkedIndexSet.remove(index)
        }
    }

    val checkedCount: Int
        get() = checkedIndexSet.size

    val checkedData: List<T>
        get() {
            val list: MutableList<T> = LinkedList()
            for (integer in checkedIndexSet) {
                list.add(getItem(integer))
            }
            return list
        }

    /**
     * 切换选中状态
     */
    fun toggle(index: Int) {
        onChecked(index, !isChecked(index))
        notifyDataSetChanged()
    }

    fun checkAll() {
        for (i in 0 until count) {
            onChecked(i, true)
        }
        notifyDataSetChanged()
    }

    fun uncheckAll() {
        checkedIndexSet.clear()
        notifyDataSetChanged()
    }

    fun getIndex(data: T): Int {
        return mDatas.indexOf(data)
    }

    fun release() {
    }

    class BindTask<T> internal constructor(private val view: BaseItemView<T>, private val data: T) :
        ThreadPoolTask() {
        init {
            key = view
        }

        override fun doInBackground() {
            if (data === view.data) {
                view.asyncBindData(data)
            }
        }
    }
}
